
/**
 * The most hated code EVER
 * Joel PC Filho
 * 01/10/2013
 */

#include"system.h"
#include<plib.h>
#include "uart.h"
#include "buffer.h"

// UART Module Definition
#if UART_MODULE == UART1A
    #define _UART_MOD   UART1
    #define _UART_VEC   _UART_1A_VECTOR
#elif UART_MODULE == UART1B
    #define _UART_MOD   UART4
    #define _UART_VEC   _UART_1B_VECTOR
#elif UART_MODULE == UART2A
    #define _UART_MOD   UART3
    #define _UART_VEC   _UART_2A_VECTOR
#elif UART_MODULE == UART2B
    #define _UART_MOD   UART6
    #define _UART_VEC   _UART_2B_VECTOR
#elif UART_MODULE == UART3A
    #define _UART_MOD   UART2
    #define _UART_VEC   _UART_3A_VECTOR
#elif UART_MODULE == UART3B
    #define _UART_MOD   UART5
    #define _UART_VEC   _UART_3B_VECTOR
#else
    #error You gotta define a UART module, bro
#endif

// Private buffer
BYTE inBuffer[64];
BYTE outBuffer[UART_BUFFER_SIZE];

buffer inputBuffer;
buffer outputBuffer;

// uart.h functions

void initUART(){

    UARTConfigure(_UART_MOD, UART_ENABLE_PINS_TX_RX_ONLY);
    UARTSetFifoMode(_UART_MOD, UART_INTERRUPT_ON_TX_DONE | UART_INTERRUPT_ON_RX_NOT_EMPTY);
    UARTSetLineControl(_UART_MOD, UART_DATA_SIZE_8_BITS | UART_PARITY_NONE | UART_STOP_BITS_1);
    UARTSetDataRate(_UART_MOD, GetPeripheralClock(), UART_BAUDRATE);
    UARTEnable(_UART_MOD, UART_ENABLE_FLAGS(UART_PERIPHERAL | UART_RX | UART_TX));

    INTEnable(INT_SOURCE_UART_RX(_UART_MOD), INT_ENABLED);
    INTEnable(INT_SOURCE_UART_TX(_UART_MOD), INT_ENABLED);

    INTSetVectorPriority(INT_VECTOR_UART(_UART_MOD), INT_PRIORITY_LEVEL_2);
    INTSetVectorSubPriority(INT_VECTOR_UART(_UART_MOD), INT_SUB_PRIORITY_LEVEL_0);

    buildBuffer(&inputBuffer, inBuffer, 64);
    buildBuffer(&outputBuffer, outBuffer, UART_BUFFER_SIZE);

}

void flushBuffer(){
    while(UARTTransmitterIsReady(_UART_MOD) && !emptyBuffer(&outputBuffer)){
        UARTSendDataByte(_UART_MOD, nextBufferChar(&outputBuffer));
    }
}

BYTE idleUART(){
    return UARTTransmissionHasCompleted(_UART_MOD);
}

BYTE availableUART(){
    return !fullBuffer(&outputBuffer);
}

BYTE sendString(const char *str){
    bufferize(&outputBuffer, str);
    INTEnable(INT_SOURCE_UART_TX(_UART_MOD), INT_ENABLED);
    flushBuffer();
}

BYTE dataAvailable(){
    return !emptyBuffer(&inputBuffer);
}

BYTE readUART(){
    return nextBufferChar(&inputBuffer);
}

void __ISR(_UART_VEC, ipl2) IntUart1Handler(void)
{
	// RX interrupt
	if(INTGetFlag(INT_SOURCE_UART_RX(_UART_MOD)))
	{

                INTClearFlag(INT_SOURCE_UART_RX(_UART_MOD));
                
                while(UARTReceivedDataIsAvailable(_UART_MOD) && !fullBuffer(&inputBuffer)){
                    bufferizeChar(&inputBuffer, UARTGetDataByte(_UART_MOD));
                }

                newDataUART();

	}

	// TX interrupt
	if ( INTGetFlag(INT_SOURCE_UART_TX(_UART_MOD)) )
	{
		// Toggle LED to indicate UART activity
		//mPORTDToggleBits(BIT_0);
                INTClearFlag(INT_SOURCE_UART_TX(_UART_MOD));
                if(emptyBuffer(&outputBuffer)){
                    INTEnable(INT_SOURCE_UART_TX(_UART_MOD), INT_DISABLED);
                    transmissionEndUART();
                } else
                    flushBuffer();
	}
}